package com.example.usercenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.usercenter.common.ErrorCode;
import com.example.usercenter.exception.ServiceException;
import com.example.usercenter.model.domain.Team;
import com.example.usercenter.model.domain.TeamUser;
import com.example.usercenter.model.domain.User;
import com.example.usercenter.model.request.*;
import com.example.usercenter.model.vo.TeamVO;
import com.example.usercenter.model.vo.UserVO;
import com.example.usercenter.service.TeamService;
import com.example.usercenter.mapper.TeamMapper;
import com.example.usercenter.service.TeamUserService;
import com.example.usercenter.service.UserService;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author 57017
* @description 针对表【t_team(队伍表)】的数据库操作Service实现
* @createDate 2024-05-17 13:11:57
*/
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>
    implements TeamService{

    @Resource
    private TeamUserService teamUserService;
    @Resource
    private UserService userService;

    @Transactional
    @Override
    public Long createTeam(TeamCreateRequest teamCreateRequest, User loginUser) {
        // 1. 参数非空校验
        if (teamCreateRequest == null) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 校验参数是否为登录态
        if (loginUser == null) {
            throw new ServiceException(ErrorCode.NO_LOGIN);
        }
        // 3. 校验参数字段
        // 3.1 校验队伍名称
        String teamName = teamCreateRequest.getTeamName();
        if (StringUtils.isBlank(teamName) || teamName.length() > 20) {
            throw new ServiceException(500, "队伍名称不符合要求！");
        }
        // 3.2 校验队伍描述信息
        String teamDesc = teamCreateRequest.getTeamDesc();
        if (StringUtils.isBlank(teamDesc) || teamDesc.length() > 50) {
            throw new ServiceException(500, "队伍描述不符合要求！");
        }
        // 3.3 校验队伍最大人数信息
        Integer teamMaxinum = teamCreateRequest.getTeamMaxinum();
        if (teamMaxinum == null || teamMaxinum <= 1 || teamMaxinum > 20) {
            throw new ServiceException(500, "队伍最大人数不符合要求！");
        }
        // 3.4 校验队伍过期时间
        Date teamExpireTime = teamCreateRequest.getTeamExpireTime();
        if (teamExpireTime == null || teamExpireTime.before(new Date())) {
            throw new ServiceException(500, "队伍过期时间不符合要求！");
        }
        // 3.5 校验用户是否选择密码房
        Integer teamStatus = teamCreateRequest.getTeamStatus();
        String teamPwd = teamCreateRequest.getTeamPwd();
        if (teamStatus == null || teamStatus == 0 && !teamPwd.equals("")) {
            // 公开房但是出现了密码
            throw new ServiceException(ErrorCode.PARAMS_ERROR);
        }
        if (teamStatus == 1) {
            // 是密码房但是密码不符合要求
            if (StringUtils.isBlank(teamPwd) || teamPwd.length() < 4 || teamPwd.length() > 8) {
                throw new ServiceException(500, "密码不符合要求！");
            }
        }
        // 4. 校验用户最多创建和加入5个队伍
        long createCount = teamUserService.count(new QueryWrapper<TeamUser>()
                .eq("user_id", loginUser.getId()));
        if (createCount >= 5) {
            throw new ServiceException(500, "用户加入队伍数已达上限！");
        }
        // 5. 向数据库中插入用户数据
        Team team = new Team();
        BeanUtils.copyProperties(teamCreateRequest, team);
        team.setUserId(loginUser.getId()); // 需要设置创建人id
        TeamUser teamUser = new TeamUser();
        boolean saveTeamRes = this.save(team);
        teamUser.setTeamId(team.getId());
        teamUser.setUserId(loginUser.getId());
        teamUser.setJoinTime(new Date());
        boolean saveTeamUserRes = teamUserService.save(teamUser);
        if (!saveTeamRes || !saveTeamUserRes) {
            throw new ServiceException(500, "创建队伍失败！");
        }
        return team.getId();
    }

    @Override
    public boolean addTeam(TeamAddRequest teamAddRequest, User loginUser) {
        // 1. 参数非空校验
        if (teamAddRequest == null) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 用户登录态校验
        if (loginUser == null) {
            throw new ServiceException(ErrorCode.NO_LOGIN);
        }
        // 3. 逻辑校验
        // 3.1 校验队伍id是否存在
        Long teamId = teamAddRequest.getId();
        if (teamId == null || teamId <= 0) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR);
        }
        Team dbTeam = this.getById(teamId);
        if (dbTeam == null) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR);
        }
        // 3.2 校验队伍是否过期
        Date teamExpireTime = dbTeam.getTeamExpireTime();
        if (teamExpireTime.before(new Date())) {
            throw new ServiceException(500, "队伍已经过期！");
        }
        // 3.3 校验是否为密码房并校验密码
        Integer teamStatus = dbTeam.getTeamStatus();
        String pwd = teamAddRequest.getTeamPwd();
        if (teamStatus == 0 && !"".equals(pwd)) {
            throw new ServiceException(500, "房间密码错误！");
        }
        if (teamStatus == 1 && !dbTeam.getTeamPwd().equals(pwd)) {
            throw new ServiceException(500, "房间密码错误！");
        }
        // 加锁防止用户疯狂点击（保证线程安全）
        synchronized (this) {
            // 3.4 校验队伍人数是否已达上限
            QueryWrapper<TeamUser> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("team_id", teamId);
            long teamMemberCount = teamUserService.count(queryWrapper);
            if (teamMemberCount == dbTeam.getTeamMaxinum()) {
                throw new ServiceException(500, "该队伍人数已满！");
            }
            // 3.5 校验用户是否重复加入队伍
            queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("team_id", teamId)
                    .eq("user_id", loginUser.getId());
            long curUserTeamCount = teamUserService.count(queryWrapper);
            if (curUserTeamCount >= 1) {
                throw new ServiceException(500, "用户不得重复加入队伍！");
            }
            // 3.6 校验用户一共加入的队伍数目是否达到上限
            queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", loginUser.getId());
            long curUserAddCount = teamUserService.count(queryWrapper);
            if (curUserAddCount >= 5) {
                throw new ServiceException(500, "用户加入队伍数已达上限！");
            }
            // 4. 插入数据库
            TeamUser teamUser = new TeamUser();
            teamUser.setUserId(loginUser.getId());
            teamUser.setTeamId(teamId);
            teamUser.setJoinTime(new Date());
            return teamUserService.save(teamUser);
        }
    }

    @Transactional
    @Override
    public boolean quitTeam(TeamQuitRequest teamQuitRequest, User loginUser) {
        // 1. 参数非空校验
        if (teamQuitRequest == null) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 校验用户登录状态
        if (loginUser == null) {
            throw new ServiceException(ErrorCode.NO_LOGIN);
        }
        // 3. 逻辑校验
        // 3.1 校验队伍是否存在
        Long teamId = teamQuitRequest.getTeamId();
        if (teamId == null || teamId <= 0) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR);
        }
        Team dbTeam = this.getById(teamId);
        if (dbTeam == null) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR);

        }
        // 3.2 校验用户是否是该队成员
        QueryWrapper<TeamUser> queryWrapper = new QueryWrapper<>();
        Long userId = loginUser.getId();
        queryWrapper.eq("team_id", teamId)
                .eq("user_id", userId);
        long matchCount = teamUserService.count(queryWrapper);
        if (matchCount == 0) {
            throw new ServiceException(500, "该用户非本队成员！");
        }
        // 3.3 校验队伍人数
        queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("team_id", teamId);
        long teamMemberCount = teamUserService.count(queryWrapper);
        if (teamMemberCount == 1) {
            // 直接解散
            teamUserService.remove(new QueryWrapper<TeamUser>()
                    .eq("team_id", teamId)
                    .eq("user_id", userId));
            this.removeById(teamId);
            return true;
        }
        // 3.4 校验是否是队长退出（如果是队长就进行顺位继承）
        if (userId.equals(dbTeam.getUserId())) {
            // 是队长退出
            QueryWrapper<TeamUser> query = new QueryWrapper<>();
            query.eq("team_id", teamId)
                    .orderByAsc("join_time")
                    .last("limit 0,2");
            TeamUser teamUser = teamUserService.list(query).get(1);
            Team newTeam = new Team();
            newTeam.setId(teamId);
            newTeam.setUserId(teamUser.getUserId());
            this.updateById(newTeam);
        }
        // 队员退出
        return teamUserService.remove(new QueryWrapper<TeamUser>()
                .eq("team_id", teamId)
                .eq("user_id", userId));
    }

    @Override
    public List<TeamVO> showTeamList() {
        return showTeamListByCondition(null);
    }

    /**
     * 根据搜索条件展示队伍列表
     * @param queryWrapper 搜索条件
     * @return 符合条件队伍列表
     */
    private List<TeamVO> showTeamListByCondition(QueryWrapper<Team> queryWrapper) {
        List<Team> dbTeamList = this.list(queryWrapper);
        List<TeamVO> retList = new ArrayList<>();
        for (Team dbTeam : dbTeamList) {
            // 1. 封装成VO返回类型
            TeamVO retTeam = new TeamVO();
            BeanUtils.copyProperties(dbTeam, retTeam);
            // 2. 关联查询队伍成员列表
            List<TeamUser> teamUserList = teamUserService.list(new QueryWrapper<TeamUser>()
                    .eq("team_id", retTeam.getId()));
            List<UserVO> memberList = new ArrayList<>();
            for (TeamUser teamUser : teamUserList) {
                Long userId = teamUser.getUserId();
                User user = userService.getById(userId);
                UserVO userVO = new UserVO();
                BeanUtils.copyProperties(user, userVO);
                memberList.add(userVO);
            }
            retTeam.setMemberList(memberList);
            retList.add(retTeam);
        }
        return retList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean dissolutionTeam(TeamDissolutionRequest teamDissolutionRequest, User loginUser) {
        // 1. 参数非空校验
        if (teamDissolutionRequest == null) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 校验用户是否为登录态
        if (loginUser == null) {
            throw new ServiceException(ErrorCode.NO_LOGIN);
        }
        // 3. 校验用户传入teamId
        Long teamId = teamDissolutionRequest.getTeamId();
        if (teamId == null || teamId <= 0) {
            throw new ServiceException(ErrorCode.PARAMS_ERROR);
        }
        Team dbTeam = this.getById(teamId);
        if (dbTeam == null) {
            throw new ServiceException(500, "该队伍不存在！");
        }
        // 4. 校验队伍过期时间
        if (dbTeam.getTeamExpireTime().before(new Date())) {
            throw new ServiceException(500, "该队伍已过期！");
        }
        // 5. 校验该用户是否是该队队长
        long userId = loginUser.getId();
        if (userId != dbTeam.getUserId()) {
            throw new ServiceException(ErrorCode.NO_AUTH);
        }
        // 6. 进行删除逻辑
        boolean removeTeamUserRes = teamUserService.remove(new QueryWrapper<TeamUser>()
                .eq("team_id", teamId)
        );
        if (!removeTeamUserRes) {
            throw new ServiceException(500, "删除队伍失败！");
        }
        boolean removeTeamRes = this.removeById(teamId);
        if (!removeTeamRes) {
            throw new ServiceException(500, "删除队伍失败！");
        }
        return true;
    }

    @Override
    public Boolean updateTeam(TeamUpdateRequest teamUpdateRequest, User loginUser) {
        // 1. 参数非空校验
        if (teamUpdateRequest == null) {
            throw new ServiceException(ErrorCode.PARAMS_NULL);
        }
        // 2. 校验参数是否为登录态
        if (loginUser == null) {
            throw new ServiceException(ErrorCode.NO_LOGIN);
        }
        // 3. 校验参数字段
        // 3.1 校验队伍名称
        String teamName = teamUpdateRequest.getTeamName();
        if (StringUtils.isBlank(teamName) || teamName.length() > 20) {
            throw new ServiceException(500, "队伍名称不符合要求！");
        }
        // 3.2 校验队伍描述信息
        String teamDesc = teamUpdateRequest.getTeamDesc();
        if (StringUtils.isBlank(teamDesc) || teamDesc.length() > 50) {
            throw new ServiceException(500, "队伍描述不符合要求！");
        }
        // 3.3 校验用户是否选择密码房
        Integer teamStatus = teamUpdateRequest.getTeamStatus();
        String teamPwd = teamUpdateRequest.getTeamPwd();
        if (teamStatus == null || (teamStatus == 0 && !teamPwd.equals(""))) {
            // 公开房但是出现了密码
            throw new ServiceException(ErrorCode.PARAMS_ERROR);
        }
        if (teamStatus == 1) {
            // 是密码房但是密码不符合要求
            if (StringUtils.isBlank(teamPwd) || teamPwd.length() < 4 || teamPwd.length() > 8) {
                throw new ServiceException(500, "密码不符合要求！");
            }
        }
        // 3.4 校验队伍id
        Long teamId = teamUpdateRequest.getId();
        if (teamId == null || teamId <= 0) {
            throw new ServiceException(500, "该队伍不存在！");
        }
        Team dbTeam = this.getById(teamId);
        if (dbTeam == null) {
            throw new ServiceException(500, "该队伍不存在！");
        }
        // 3.5 校验修改人是否是房主
        Long userId = loginUser.getId();
        if (!userId.equals(dbTeam.getUserId())) {
            throw new ServiceException(ErrorCode.NO_AUTH);
        }
        // 4. 修改队伍信息
        Team teamBean = new Team();
        BeanUtils.copyProperties(teamUpdateRequest, teamBean);
        boolean updateRes = this.updateById(teamBean);
        if (!updateRes) {
            throw new ServiceException(500, "更新队伍信息失败！");
        }
        return true;
    }

    @Override
    public List<TeamVO> showCreateTeamList(User loginUser) {
        // 1. 校验用户登录态
        if (loginUser == null) {
            throw new ServiceException(ErrorCode.NO_LOGIN);
        }
        // 2. 查询user_id为loginId的用户
        long loginId = loginUser.getId();
        QueryWrapper<Team> queryWrapper = new QueryWrapper<Team>()
                .eq("user_id", loginId);
        // 3. 返回队伍列表信息
        return showTeamListByCondition(queryWrapper);
    }

    @Override
    public List<TeamVO> showJoinTeamList(User loginUser) {
        // 1. 校验用户登录态
        if (loginUser == null) {
            throw new ServiceException(ErrorCode.NO_LOGIN);
        }
        // 2. 查询user_id为loginId的用户
        long loginId = loginUser.getId();
        QueryWrapper<TeamUser> queryWrapper = new QueryWrapper<TeamUser>()
                .eq("user_id", loginId);
        // 3. 获取该用户加入的全部队伍id
        List<Long> idList = teamUserService.list(queryWrapper)
                .stream().map(TeamUser::getTeamId)
                .collect(Collectors.toList());
        // 4. 以队伍id在idList中作为查询条件
        return showTeamListByCondition(new QueryWrapper<Team>()
                .in("id", idList));
    }
}




